1use std::num::NonZero;
2
3use crate::common::Rational32;
4
5#[derive(Clone, Copy, Hash, PartialEq, Eq)]
7pub struct ObjectHandle {
8 pub(crate) internal: aviutl2_sys::plugin2::OBJECT_HANDLE,
9}
10impl std::fmt::Debug for ObjectHandle {
11 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12 f.debug_tuple("ObjectHandle").field(&self.internal).finish()
13 }
14}
15impl From<aviutl2_sys::plugin2::OBJECT_HANDLE> for ObjectHandle {
16 fn from(value: aviutl2_sys::plugin2::OBJECT_HANDLE) -> Self {
17 Self { internal: value }
18 }
19}
20impl From<ObjectHandle> for aviutl2_sys::plugin2::OBJECT_HANDLE {
21 fn from(value: ObjectHandle) -> Self {
22 value.internal
23 }
24}
25
26unsafe impl Send for ObjectHandle {}
28unsafe impl Sync for ObjectHandle {}
29
30#[derive(Debug, Clone, Copy)]
36pub struct EditInfo {
37 pub width: usize,
39 pub height: usize,
41 pub fps: Rational32,
43 pub sample_rate: usize,
45 pub frame: usize,
47 pub layer: usize,
49 pub frame_max: usize,
51 pub layer_max: usize,
53 pub display_frame_start: usize,
55 pub display_layer_start: usize,
57 pub display_frame_num: usize,
63 pub display_layer_num: usize,
69 pub select_range_start: Option<usize>,
72 pub select_range_end: Option<usize>,
75 pub grid_bpm_tempo: f32,
77 pub grid_bpm_beat: usize,
79 pub grid_bpm_offset: f32,
81 pub scene_id: i32,
83}
84
85impl EditInfo {
86 pub unsafe fn from_raw(ptr: *const aviutl2_sys::plugin2::EDIT_INFO) -> Self {
90 let raw = unsafe { &*ptr };
91 Self {
92 width: raw.width as usize,
93 height: raw.height as usize,
94 fps: Rational32::new(raw.rate, raw.scale),
95 sample_rate: raw.sample_rate as usize,
96 frame: raw.frame as usize,
97 layer: raw.layer as usize,
98 frame_max: raw.frame_max as usize,
99 layer_max: raw.layer_max as usize,
100 display_frame_start: raw.display_frame_start as usize,
101 display_layer_start: raw.display_layer_start as usize,
102 display_frame_num: raw.display_frame_num as usize,
103 display_layer_num: raw.display_layer_num as usize,
104
105 select_range_start: (raw.select_range_start >= 0)
106 .then_some(raw.select_range_start as usize),
107 select_range_end: (raw.select_range_end >= 0).then_some(raw.select_range_end as usize),
108
109 grid_bpm_tempo: raw.grid_bpm_tempo,
110 grid_bpm_beat: raw.grid_bpm_beat as usize,
111 grid_bpm_offset: raw.grid_bpm_offset,
112 scene_id: raw.scene_id,
113 }
114 }
115}
116
117#[derive(Debug, Clone, Copy)]
119pub struct ObjectLayerFrame {
120 pub layer: usize,
121 pub start: usize,
122 pub end: usize,
123}
124
125impl ObjectLayerFrame {
126 pub fn frame_range(&self) -> std::ops::Range<usize> {
128 self.start..(self.end + 1)
129 }
130
131 pub fn frame_range_inclusive(&self) -> std::ops::RangeInclusive<usize> {
133 self.start..=self.end
134 }
135}
136
137#[derive(Debug, Clone, Copy)]
139pub struct LayerFrameData {
140 pub layer: usize,
141 pub frame: usize,
142}
143
144#[derive(Debug, Clone, Copy)]
145pub struct MediaInfo {
146 pub video_track_num: Option<NonZero<usize>>,
148 pub audio_track_num: Option<NonZero<usize>>,
150 pub total_time: f64,
152 pub width: usize,
154 pub height: usize,
156}
157
158#[derive(Debug, Clone, Copy)]
160pub enum MediaFileSupportMode {
161 ExtensionOnly,
163 Strict,
165}
166
167#[derive(thiserror::Error, Debug)]
169pub enum EditSectionError {
170 #[error("api call failed")]
171 ApiCallFailed,
172 #[error("object does not exist")]
173 ObjectDoesNotExist,
174 #[error("input utf-8 string contains null byte")]
175 InputCstrContainsNull(#[from] std::ffi::NulError),
176 #[error("input utf-16 string contains null byte")]
177 InputCwstrContainsNull(#[from] crate::common::NullByteError),
178 #[error("value is out of range")]
179 ValueOutOfRange(#[from] std::num::TryFromIntError),
180 #[error("api returned non-utf8 data")]
181 NonUtf8Data(#[from] std::str::Utf8Error),
182
183 #[cfg(feature = "aviutl2-alias")]
184 #[error("alias parse error: {0}")]
185 ParseFailed(#[from] aviutl2_alias::TableParseError),
186}
187
188#[derive(thiserror::Error, Debug)]
190pub enum EditSectionParsedError<E: std::error::Error + Send + Sync + 'static> {
191 #[error(transparent)]
192 EditSectionError(#[from] EditSectionError),
193 #[error("value parse error: {0}")]
194 ParseError(E),
195}
196
197pub type EditSectionResult<T> = Result<T, EditSectionError>;
198
199#[derive(Debug)]
201pub struct ReadSection {
202 pub(crate) internal: *mut aviutl2_sys::plugin2::EDIT_SECTION,
203}
204
205#[derive(Debug)]
207pub struct EditSection {
208 pub info: EditInfo,
210
211 pub(crate) internal: *mut aviutl2_sys::plugin2::EDIT_SECTION,
212 read_section: ReadSection,
213}
214
215impl std::ops::Deref for EditSection {
216 type Target = ReadSection;
217
218 fn deref(&self) -> &Self::Target {
219 &self.read_section
220 }
221}
222
223impl ReadSection {
224 pub unsafe fn from_raw(ptr: *mut aviutl2_sys::plugin2::EDIT_SECTION) -> Self {
230 Self { internal: ptr }
231 }
232
233 pub fn find_object_after(
240 &self,
241 layer: usize,
242 frame: usize,
243 ) -> EditSectionResult<Option<ObjectHandle>> {
244 let object_handle =
245 unsafe { ((*self.internal).find_object)(layer.try_into()?, frame.try_into()?) };
246 if object_handle.is_null() {
247 Ok(None)
248 } else {
249 Ok(Some(ObjectHandle {
250 internal: object_handle,
251 }))
252 }
253 }
254
255 pub fn count_object_effect(
257 &self,
258 object: ObjectHandle,
259 effect: &str,
260 ) -> EditSectionResult<usize> {
261 self.ensure_object_exists(object)?;
262 let c_effect = crate::common::CWString::new(effect)?;
263 let count =
264 unsafe { ((*self.internal).count_object_effect)(object.internal, c_effect.as_ptr()) };
265 Ok(count.try_into()?)
266 }
267
268 pub fn get_object_layer_frame(
270 &self,
271 object: ObjectHandle,
272 ) -> EditSectionResult<ObjectLayerFrame> {
273 self.ensure_object_exists(object)?;
274 let object = unsafe { ((*self.internal).get_object_layer_frame)(object.internal) };
275 Ok(ObjectLayerFrame {
276 layer: object.layer.try_into()?,
277 start: object.start.try_into()?,
278 end: object.end.try_into()?,
279 })
280 }
281
282 pub fn get_object_alias(&self, object: ObjectHandle) -> EditSectionResult<String> {
284 self.ensure_object_exists(object)?;
285 let alias_ptr = unsafe { ((*self.internal).get_object_alias)(object.internal) };
286 if alias_ptr.is_null() {
287 return Err(EditSectionError::ApiCallFailed);
288 }
289 let c_str = unsafe { std::ffi::CStr::from_ptr(alias_ptr) };
290 let alias = c_str.to_str()?.to_owned();
291 Ok(alias)
292 }
293
294 #[cfg(feature = "aviutl2-alias")]
296 pub fn get_object_alias_parsed(
297 &self,
298 object: ObjectHandle,
299 ) -> Result<aviutl2_alias::Table, EditSectionParsedError<aviutl2_alias::TableParseError>> {
300 let alias_str = self.get_object_alias(object)?;
301 let alias_data = alias_str
302 .parse()
303 .map_err(EditSectionParsedError::ParseError)?;
304 Ok(alias_data)
305 }
306
307 pub fn get_object_name(&self, object: ObjectHandle) -> EditSectionResult<Option<String>> {
309 self.ensure_object_exists(object)?;
310 let name_ptr = unsafe { ((*self.internal).get_object_name)(object.internal) };
311 if name_ptr.is_null() {
312 return Ok(None);
313 }
314 Ok(Some(unsafe { crate::common::load_wide_string(name_ptr) }))
315 }
316
317 pub fn get_object_effect_item(
319 &self,
320 object: ObjectHandle,
321 effect_name: &str,
322 effect_index: usize,
323 item: &str,
324 ) -> EditSectionResult<String> {
325 self.ensure_object_exists(object)?;
326 let c_effect_name = crate::common::CWString::new(&effect_key(effect_name, effect_index))?;
327 let c_item = crate::common::CWString::new(item)?;
328 let value_ptr = unsafe {
329 ((*self.internal).get_object_item_value)(
330 object.internal,
331 c_effect_name.as_ptr(),
332 c_item.as_ptr(),
333 )
334 };
335 if value_ptr.is_null() {
336 return Err(EditSectionError::ApiCallFailed);
337 }
338 let c_str = unsafe { std::ffi::CStr::from_ptr(value_ptr) };
339 let value = c_str.to_str()?.to_owned();
340 Ok(value)
341 }
342
343 #[cfg(feature = "aviutl2-alias")]
345 pub fn get_object_effect_item_parsed<T: aviutl2_alias::FromTableValue>(
346 &self,
347 object: ObjectHandle,
348 effect_name: &str,
349 effect_index: usize,
350 item: &str,
351 ) -> Result<T, EditSectionParsedError<<T as aviutl2_alias::FromTableValue>::Err>>
352 where
353 <T as aviutl2_alias::FromTableValue>::Err: std::error::Error + Sync + Send + 'static,
354 {
355 let value_str = self.get_object_effect_item(object, effect_name, effect_index, item)?;
356 T::from_table_value(&value_str).map_err(EditSectionParsedError::ParseError)
357 }
358
359 pub fn get_focused_object(&self) -> EditSectionResult<Option<ObjectHandle>> {
361 let object_handle = unsafe { ((*self.internal).get_focus_object)() };
362 if object_handle.is_null() {
363 Ok(None)
364 } else {
365 Ok(Some(ObjectHandle {
366 internal: object_handle,
367 }))
368 }
369 }
370
371 pub fn get_selected_objects(&self) -> EditSectionResult<Vec<ObjectHandle>> {
373 let mut handles = Vec::new();
374 let num_objects = unsafe { ((*self.internal).get_selected_object_num)() };
375 for i in 0..num_objects {
376 let object_handle = unsafe { ((*self.internal).get_selected_object)(i) };
377 if object_handle.is_null() {
378 return Err(EditSectionError::ApiCallFailed);
379 }
380 handles.push(ObjectHandle {
381 internal: object_handle,
382 });
383 }
384 Ok(handles)
385 }
386
387 pub fn is_support_media_file<P: AsRef<std::path::Path>>(
389 &self,
390 file_path: P,
391 mode: MediaFileSupportMode,
392 ) -> EditSectionResult<bool> {
393 let c_file_path = crate::common::CWString::new(&file_path.as_ref().to_string_lossy())?;
394 let is_supported = unsafe {
395 match mode {
396 MediaFileSupportMode::ExtensionOnly => {
397 ((*self.internal).is_support_media_file)(c_file_path.as_ptr(), false)
398 }
399 MediaFileSupportMode::Strict => {
400 ((*self.internal).is_support_media_file)(c_file_path.as_ptr(), true)
401 }
402 }
403 };
404 Ok(is_supported)
405 }
406
407 pub fn get_media_info<P: AsRef<std::path::Path>>(
409 &self,
410 file_path: P,
411 ) -> EditSectionResult<MediaInfo> {
412 let c_file_path = crate::common::CWString::new(&file_path.as_ref().to_string_lossy())?;
413 let mut media_info = std::mem::MaybeUninit::<aviutl2_sys::plugin2::MEDIA_INFO>::uninit();
414 let success = unsafe {
415 ((*self.internal).get_media_info)(
416 c_file_path.as_ptr(),
417 media_info.as_mut_ptr(),
418 std::mem::size_of::<aviutl2_sys::plugin2::MEDIA_INFO>() as i32,
419 )
420 };
421 if !success {
422 return Err(EditSectionError::ApiCallFailed);
423 }
424 let media_info = unsafe { media_info.assume_init() };
425 Ok(MediaInfo {
426 video_track_num: NonZero::new(media_info.video_track_num.try_into()?),
427 audio_track_num: NonZero::new(media_info.audio_track_num.try_into()?),
428 total_time: media_info.total_time,
429 width: media_info.width.try_into()?,
430 height: media_info.height.try_into()?,
431 })
432 }
433
434 pub fn get_layer_name(&self, layer: usize) -> EditSectionResult<Option<String>> {
436 let name_ptr = unsafe { ((*self.internal).get_layer_name)(layer.try_into()?) };
437 if name_ptr.is_null() {
438 return Ok(None);
439 }
440 Ok(Some(unsafe { crate::common::load_wide_string(name_ptr) }))
441 }
442
443 pub fn get_scene_name(&self) -> EditSectionResult<String> {
445 let name_ptr = unsafe { ((*self.internal).get_scene_name)() };
446 if name_ptr.is_null() {
447 return Err(EditSectionError::ApiCallFailed);
448 }
449 Ok(unsafe { crate::common::load_wide_string(name_ptr) })
450 }
451
452 pub fn get_layer_enable(&self, layer: usize) -> EditSectionResult<bool> {
454 let visible = unsafe { ((*self.internal).get_layer_enable)(layer.try_into()?) };
455 Ok(visible)
456 }
457
458 pub fn get_layer_lock(&self, layer: usize) -> EditSectionResult<bool> {
460 let locked = unsafe { ((*self.internal).get_layer_lock)(layer.try_into()?) };
461 Ok(locked)
462 }
463
464 pub fn get_object_section_num(&self, object: ObjectHandle) -> EditSectionResult<usize> {
466 self.ensure_object_exists(object)?;
467 let count = unsafe { ((*self.internal).get_object_section_num)(object.internal) };
468 Ok(count.try_into()?)
469 }
470
471 pub fn get_focus_object_section(&self) -> EditSectionResult<Option<usize>> {
473 let section = unsafe { ((*self.internal).get_focus_object_section)() };
474 if section == -1 {
475 Ok(None)
476 } else {
477 Ok(Some(section.try_into()?))
478 }
479 }
480
481 pub fn object_exists(&self, object: ObjectHandle) -> bool {
483 let object = unsafe { ((*self.internal).get_object_layer_frame)(object.internal) };
484 object.layer != -1
485 }
486
487 fn ensure_object_exists(&self, object: ObjectHandle) -> EditSectionResult<()> {
488 if !self.object_exists(object) {
489 return Err(EditSectionError::ObjectDoesNotExist);
490 }
491 Ok(())
492 }
493
494 pub fn objects_in_layer(
496 &self,
497 layer: usize,
498 ) -> EditSectionLayerObjectsIterator<'_, ReadSection> {
499 EditSectionLayerObjectsIterator::new(self, layer)
500 }
501
502 pub fn layer<'a>(&'a self, layer: usize) -> EditSectionLayerCaller<'a, ReadSection> {
504 EditSectionLayerCaller::new(self, layer)
505 }
506
507 pub fn object<'a>(&'a self, object: ObjectHandle) -> EditSectionObjectCaller<'a, ReadSection> {
509 EditSectionObjectCaller::new(self, object)
510 }
511}
512
513impl EditSection {
514 pub unsafe fn from_raw(ptr: *mut aviutl2_sys::plugin2::EDIT_SECTION) -> Self {
520 let info = unsafe { EditInfo::from_raw((*ptr).info) };
521 Self {
522 internal: ptr,
523 info,
524 read_section: ReadSection { internal: ptr },
525 }
526 }
527
528 pub fn create_object_from_alias(
544 &self,
545 alias: &str,
546 layer: usize,
547 frame: usize,
548 length: usize,
549 ) -> EditSectionResult<ObjectHandle> {
550 let c_alias = std::ffi::CString::new(alias)?;
551 let object_handle = unsafe {
552 ((*self.internal).create_object_from_alias)(
553 c_alias.as_ptr(),
554 layer.try_into()?,
555 frame.try_into()?,
556 length.try_into()?,
557 )
558 };
559 if object_handle.is_null() {
560 return Err(EditSectionError::ApiCallFailed);
561 }
562 Ok(ObjectHandle {
563 internal: object_handle,
564 })
565 }
566
567 pub fn set_object_name(
573 &self,
574 object: ObjectHandle,
575 name: Option<&str>,
576 ) -> EditSectionResult<()> {
577 self.read_section.ensure_object_exists(object)?;
578 match name {
579 None => {
580 unsafe { ((*self.internal).set_object_name)(object.internal, std::ptr::null()) };
581 Ok(())
582 }
583 Some(name) => {
584 let c_name = crate::common::CWString::new(name)?;
585 unsafe {
586 ((*self.internal).set_object_name)(object.internal, c_name.as_ptr());
587 }
588 Ok(())
589 }
590 }
591 }
592
593 pub fn set_object_effect_item(
603 &self,
604 object: ObjectHandle,
605 effect_name: &str,
606 effect_index: usize,
607 item: &str,
608 value: &str,
609 ) -> EditSectionResult<()> {
610 self.read_section.ensure_object_exists(object)?;
611 let c_effect_name = crate::common::CWString::new(&effect_key(effect_name, effect_index))?;
612 let c_item = crate::common::CWString::new(item)?;
613 let c_value = std::ffi::CString::new(value)?;
614 let success = unsafe {
615 ((*self.internal).set_object_item_value)(
616 object.internal,
617 c_effect_name.as_ptr(),
618 c_item.as_ptr(),
619 c_value.as_ptr(),
620 )
621 };
622 if !success {
623 return Err(EditSectionError::ApiCallFailed);
624 }
625 Ok(())
626 }
627
628 pub fn move_object(
630 &self,
631 object: ObjectHandle,
632 new_layer: usize,
633 new_start_frame: usize,
634 ) -> EditSectionResult<()> {
635 self.read_section.ensure_object_exists(object)?;
636 let success = unsafe {
637 ((*self.internal).move_object)(
638 object.internal,
639 new_layer.try_into()?,
640 new_start_frame.try_into()?,
641 )
642 };
643 if !success {
644 return Err(EditSectionError::ApiCallFailed);
645 }
646 Ok(())
647 }
648
649 pub fn delete_object(&self, object: ObjectHandle) -> EditSectionResult<()> {
651 self.read_section.ensure_object_exists(object)?;
652 unsafe { ((*self.internal).delete_object)(object.internal) };
653 Ok(())
654 }
655
656 pub fn focus_object(&self, object: ObjectHandle) -> EditSectionResult<()> {
662 self.read_section.ensure_object_exists(object)?;
663 unsafe { ((*self.internal).set_focus_object)(object.internal) };
664 Ok(())
665 }
666
667 pub fn get_project_file<'handle>(
669 &'handle self,
670 edit_handle: &crate::generic::EditHandle,
671 ) -> crate::generic::ProjectFile<'handle> {
672 let pf_ptr = unsafe { ((*self.internal).get_project_file)(edit_handle.internal) };
673 unsafe { crate::generic::ProjectFile::from_raw(pf_ptr) }
674 }
675
676 pub fn get_mouse_layer_frame(&self) -> EditSectionResult<Option<LayerFrameData>> {
683 let mut layer = 0;
684 let mut frame = 0;
685 let on_layer_edit =
686 unsafe { ((*self.internal).get_mouse_layer_frame)(&mut layer, &mut frame) };
687 if on_layer_edit {
688 Ok(Some(LayerFrameData {
689 layer: layer.try_into()?,
690 frame: frame.try_into()?,
691 }))
692 } else {
693 Ok(None)
694 }
695 }
696
697 pub fn pos_to_layer_frame(&self, x: i32, y: i32) -> EditSectionResult<Option<LayerFrameData>> {
699 let mut layer = 0;
700 let mut frame = 0;
701 let on_layer_edit =
702 unsafe { ((*self.internal).pos_to_layer_frame)(x, y, &mut layer, &mut frame) };
703 if on_layer_edit {
704 Ok(Some(LayerFrameData {
705 layer: layer.try_into()?,
706 frame: frame.try_into()?,
707 }))
708 } else {
709 Ok(None)
710 }
711 }
712
713 pub fn create_object_from_media_file<P: AsRef<std::path::Path>>(
722 &self,
723 file_path: P,
724 layer: usize,
725 frame: usize,
726 length: Option<usize>,
727 ) -> EditSectionResult<ObjectHandle> {
728 let c_file_path = crate::common::CWString::new(&file_path.as_ref().to_string_lossy())?;
729 let object_handle = unsafe {
730 ((*self.internal).create_object_from_media_file)(
731 c_file_path.as_ptr(),
732 layer.try_into()?,
733 frame.try_into()?,
734 length.unwrap_or(0).try_into()?,
735 )
736 };
737 if object_handle.is_null() {
738 return Err(EditSectionError::ApiCallFailed);
739 }
740 Ok(ObjectHandle {
741 internal: object_handle,
742 })
743 }
744
745 pub fn create_object(
754 &self,
755 effect: &str,
756 layer: usize,
757 frame: usize,
758 length: Option<usize>,
759 ) -> EditSectionResult<ObjectHandle> {
760 let c_effect = crate::common::CWString::new(effect)?;
761 let object_handle = unsafe {
762 ((*self.internal).create_object)(
763 c_effect.as_ptr(),
764 layer.try_into()?,
765 frame.try_into()?,
766 length.unwrap_or(0).try_into()?,
767 )
768 };
769 if object_handle.is_null() {
770 return Err(EditSectionError::ApiCallFailed);
771 }
772 Ok(ObjectHandle {
773 internal: object_handle,
774 })
775 }
776
777 pub fn set_cursor_layer_frame(&self, layer: usize, frame: usize) -> EditSectionResult<()> {
783 unsafe {
784 ((*self.internal).set_cursor_layer_frame)(layer.try_into()?, frame.try_into()?);
785 }
786 Ok(())
787 }
788
789 pub fn set_display_layer_frame(&self, layer: usize, frame: usize) -> EditSectionResult<()> {
795 unsafe {
796 ((*self.internal).set_display_layer_frame)(layer.try_into()?, frame.try_into()?);
797 }
798 Ok(())
799 }
800
801 pub fn set_select_range(&self, start: usize, end: usize) -> EditSectionResult<()> {
807 unsafe {
808 ((*self.internal).set_select_range)(start.try_into()?, end.try_into()?);
809 }
810 Ok(())
811 }
812
813 pub fn clear_select_range(&self) -> EditSectionResult<()> {
815 unsafe {
816 ((*self.internal).set_select_range)(-1, -1);
817 }
818 Ok(())
819 }
820
821 pub fn set_grid_bpm(&self, tempo: f32, beat: usize, offset: f32) -> EditSectionResult<()> {
823 unsafe {
824 ((*self.internal).set_grid_bpm)(tempo, beat.try_into()?, offset);
825 }
826 Ok(())
827 }
828
829 pub fn set_layer_name(&self, layer: usize, name: Option<&str>) -> EditSectionResult<()> {
832 match name {
833 None => {
834 unsafe { ((*self.internal).set_layer_name)(layer.try_into()?, std::ptr::null()) };
835 Ok(())
836 }
837 Some(name) => {
838 let c_name = crate::common::CWString::new(name)?;
839 unsafe {
840 ((*self.internal).set_layer_name)(layer.try_into()?, c_name.as_ptr());
841 }
842 Ok(())
843 }
844 }
845 }
846
847 pub fn set_scene_name(&self, name: &str) -> EditSectionResult<()> {
853 let c_name = crate::common::CWString::new(name)?;
854 unsafe { ((*self.internal).set_scene_name)(c_name.as_ptr()) };
855 Ok(())
856 }
857
858 pub fn set_scene_size(&self, width: usize, height: usize) -> EditSectionResult<()> {
864 unsafe {
865 ((*self.internal).set_scene_size)(width.try_into()?, height.try_into()?);
866 }
867 Ok(())
868 }
869
870 pub fn set_scene_fps(&self, fps: Rational32) -> EditSectionResult<()> {
876 unsafe {
877 ((*self.internal).set_scene_frame_rate)(*fps.numer(), *fps.denom());
878 }
879 Ok(())
880 }
881
882 pub fn set_scene_sample_rate(&self, sample_rate: usize) -> EditSectionResult<()> {
888 unsafe {
889 ((*self.internal).set_scene_sample_rate)(sample_rate.try_into()?);
890 }
891 Ok(())
892 }
893
894 pub fn set_layer_enable(&self, layer: usize, enable: bool) -> EditSectionResult<()> {
896 unsafe {
897 ((*self.internal).set_layer_enable)(layer.try_into()?, enable);
898 }
899 Ok(())
900 }
901
902 pub fn set_layer_lock(&self, layer: usize, lock: bool) -> EditSectionResult<()> {
904 unsafe {
905 ((*self.internal).set_layer_lock)(layer.try_into()?, lock);
906 }
907 Ok(())
908 }
909
910 pub fn layers(&self) -> EditSectionLayersIterator<'_> {
912 EditSectionLayersIterator::new(self)
913 }
914 pub fn objects_in_layer(
916 &self,
917 layer: usize,
918 ) -> EditSectionLayerObjectsIterator<'_, EditSection> {
919 EditSectionLayerObjectsIterator::new(self, layer)
920 }
921
922 pub fn layer<'a>(&'a self, layer: usize) -> EditSectionLayerCaller<'a, EditSection> {
924 EditSectionLayerCaller::new(self, layer)
925 }
926 pub fn object<'a>(&'a self, object: ObjectHandle) -> EditSectionObjectCaller<'a, EditSection> {
928 EditSectionObjectCaller::new(self, object)
929 }
930}
931
932trait ReadSectionProvider {
933 fn as_read_section(&self) -> &ReadSection;
934}
935
936impl ReadSectionProvider for ReadSection {
937 fn as_read_section(&self) -> &ReadSection {
938 self
939 }
940}
941
942impl ReadSectionProvider for EditSection {
943 fn as_read_section(&self) -> &ReadSection {
944 &self.read_section
945 }
946}
947
948pub struct EditSectionObjectCaller<'a, S> {
952 edit_section: &'a S,
953 pub handle: ObjectHandle,
954}
955impl<'a, S> EditSectionObjectCaller<'a, S> {
956 pub fn new(edit_section: &'a S, object: ObjectHandle) -> Self {
957 Self {
958 edit_section,
959 handle: object,
960 }
961 }
962}
963
964impl<S> std::ops::Deref for EditSectionObjectCaller<'_, S> {
965 type Target = ObjectHandle;
966
967 fn deref(&self) -> &Self::Target {
968 &self.handle
969 }
970}
971
972#[expect(private_bounds)]
973impl<S> EditSectionObjectCaller<'_, S>
974where
975 S: ReadSectionProvider,
976{
977 fn read_section(&self) -> &ReadSection {
978 self.edit_section.as_read_section()
979 }
980
981 pub fn get_layer_frame(&self) -> EditSectionResult<ObjectLayerFrame> {
983 self.read_section().get_object_layer_frame(self.handle)
984 }
985
986 pub fn get_alias(&self) -> EditSectionResult<String> {
988 self.read_section().get_object_alias(self.handle)
989 }
990
991 #[cfg(feature = "aviutl2-alias")]
993 pub fn get_alias_parsed(&self) -> EditSectionResult<aviutl2_alias::Table> {
994 self.read_section()
995 .get_object_alias(self.handle)?
996 .parse()
997 .map_err(Into::into)
998 }
999
1000 pub fn count_effect(&self, effect: &str) -> EditSectionResult<usize> {
1010 self.read_section().count_object_effect(self.handle, effect)
1011 }
1012
1013 pub fn get_effect_item(
1021 &self,
1022 effect_name: &str,
1023 effect_index: usize,
1024 item: &str,
1025 ) -> EditSectionResult<String> {
1026 self.read_section()
1027 .get_object_effect_item(self.handle, effect_name, effect_index, item)
1028 }
1029
1030 #[cfg(feature = "aviutl2-alias")]
1036 pub fn get_effect_item_parsed<T: aviutl2_alias::FromTableValue>(
1037 &self,
1038 effect_name: &str,
1039 effect_index: usize,
1040 item: &str,
1041 ) -> Result<T, EditSectionParsedError<<T as aviutl2_alias::FromTableValue>::Err>>
1042 where
1043 <T as aviutl2_alias::FromTableValue>::Err: std::error::Error + Sync + Send + 'static,
1044 {
1045 let value_str = self.get_effect_item(effect_name, effect_index, item)?;
1046 T::from_table_value(&value_str).map_err(EditSectionParsedError::ParseError)
1047 }
1048
1049 pub fn exists(&self) -> bool {
1051 self.read_section().object_exists(self.handle)
1052 }
1053
1054 pub fn get_name(&self) -> EditSectionResult<Option<String>> {
1060 self.read_section().get_object_name(self.handle)
1061 }
1062
1063 pub fn get_section_num(&self) -> EditSectionResult<usize> {
1065 self.read_section().get_object_section_num(self.handle)
1066 }
1067}
1068
1069impl EditSectionObjectCaller<'_, EditSection> {
1070 pub fn set_effect_item(
1079 &self,
1080 effect_name: &str,
1081 effect_index: usize,
1082 item: &str,
1083 value: &str,
1084 ) -> EditSectionResult<()> {
1085 self.edit_section.set_object_effect_item(
1086 self.handle,
1087 effect_name,
1088 effect_index,
1089 item,
1090 value,
1091 )
1092 }
1093
1094 pub fn move_object(&self, new_layer: usize, new_start_frame: usize) -> EditSectionResult<()> {
1101 self.edit_section
1102 .move_object(self.handle, new_layer, new_start_frame)
1103 }
1104
1105 pub fn delete_object(&self) -> EditSectionResult<()> {
1107 self.edit_section.delete_object(self.handle)
1108 }
1109
1110 pub fn focus_object(&self) -> EditSectionResult<()> {
1116 self.edit_section.focus_object(self.handle)
1117 }
1118
1119 pub fn set_name(&self, name: Option<&str>) -> EditSectionResult<()> {
1122 self.edit_section.set_object_name(self.handle, name)
1123 }
1124}
1125
1126pub struct EditSectionLayerCaller<'a, S> {
1130 edit_section: &'a S,
1131 pub index: usize,
1132}
1133impl<'a, S> EditSectionLayerCaller<'a, S> {
1134 pub fn new(edit_section: &'a S, layer: usize) -> Self {
1135 Self {
1136 edit_section,
1137 index: layer,
1138 }
1139 }
1140}
1141
1142#[expect(private_bounds)]
1143impl<S> EditSectionLayerCaller<'_, S>
1144where
1145 S: ReadSectionProvider,
1146{
1147 fn read_section(&self) -> &ReadSection {
1148 self.edit_section.as_read_section()
1149 }
1150
1151 pub fn find_object_after(&self, frame: usize) -> EditSectionResult<Option<ObjectHandle>> {
1157 self.read_section().find_object_after(self.index, frame)
1158 }
1159
1160 pub fn get_name(&self) -> EditSectionResult<Option<String>> {
1162 self.read_section().get_layer_name(self.index)
1163 }
1164
1165 pub fn get_enable(&self) -> EditSectionResult<bool> {
1167 self.read_section().get_layer_enable(self.index)
1168 }
1169
1170 pub fn get_lock(&self) -> EditSectionResult<bool> {
1172 self.read_section().get_layer_lock(self.index)
1173 }
1174
1175 pub fn objects(&self) -> EditSectionLayerObjectsIterator<'_, S> {
1178 EditSectionLayerObjectsIterator::new(self.edit_section, self.index)
1179 }
1180}
1181
1182impl EditSectionLayerCaller<'_, EditSection> {
1183 pub fn create_object_from_alias<P: AsRef<std::path::Path>>(
1189 &self,
1190 alias: &str,
1191 frame: usize,
1192 length: usize,
1193 ) -> EditSectionResult<ObjectHandle> {
1194 self.edit_section
1195 .create_object_from_alias(alias, self.index, frame, length)
1196 }
1197
1198 pub fn create_object_from_media_file<P: AsRef<std::path::Path>>(
1204 &self,
1205 file_path: P,
1206 frame: usize,
1207 length: Option<usize>,
1208 ) -> EditSectionResult<ObjectHandle> {
1209 self.edit_section
1210 .create_object_from_media_file(file_path, self.index, frame, length)
1211 }
1212
1213 pub fn create_object(
1219 &self,
1220 effect: &str,
1221 frame: usize,
1222 length: Option<usize>,
1223 ) -> EditSectionResult<ObjectHandle> {
1224 self.edit_section
1225 .create_object(effect, self.index, frame, length)
1226 }
1227
1228 pub fn set_name(&self, name: Option<&str>) -> EditSectionResult<()> {
1231 self.edit_section.set_layer_name(self.index, name)
1232 }
1233
1234 pub fn set_enable(&self, enable: bool) -> EditSectionResult<()> {
1236 self.edit_section.set_layer_enable(self.index, enable)
1237 }
1238
1239 pub fn set_lock(&self, lock: bool) -> EditSectionResult<()> {
1241 self.edit_section.set_layer_lock(self.index, lock)
1242 }
1243}
1244
1245#[derive(Debug, Clone)]
1247pub struct EditSectionLayersIterator<'a> {
1248 edit_section: &'a EditSection,
1249 current: usize,
1250 end: usize,
1251}
1252
1253impl<'a> EditSectionLayersIterator<'a> {
1254 fn new(edit_section: &'a EditSection) -> Self {
1255 Self {
1256 edit_section,
1257 current: 0,
1258 end: edit_section.info.layer_max.saturating_add(1),
1259 }
1260 }
1261}
1262
1263impl<'a> Iterator for EditSectionLayersIterator<'a> {
1264 type Item = EditSectionLayerCaller<'a, EditSection>;
1265
1266 fn next(&mut self) -> Option<Self::Item> {
1267 if self.current >= self.end {
1268 return None;
1269 }
1270 let layer = self.current;
1271 self.current += 1;
1272 Some(EditSectionLayerCaller::new(self.edit_section, layer))
1273 }
1274
1275 fn size_hint(&self) -> (usize, Option<usize>) {
1276 let len = self.end.saturating_sub(self.current);
1277 (len, Some(len))
1278 }
1279}
1280
1281impl<'a> DoubleEndedIterator for EditSectionLayersIterator<'a> {
1282 fn next_back(&mut self) -> Option<Self::Item> {
1283 if self.current >= self.end {
1284 return None;
1285 }
1286 self.end -= 1;
1287 Some(EditSectionLayerCaller::new(self.edit_section, self.end))
1288 }
1289}
1290
1291impl ExactSizeIterator for EditSectionLayersIterator<'_> {}
1292
1293#[derive(Debug, Clone)]
1296pub struct EditSectionLayerObjectsIterator<'a, S> {
1297 edit_section: &'a S,
1298 layer: usize,
1299 next_frame: usize,
1300}
1301
1302impl<'a, S> EditSectionLayerObjectsIterator<'a, S> {
1303 fn new(edit_section: &'a S, layer: usize) -> Self {
1304 Self {
1305 edit_section,
1306 layer,
1307 next_frame: 0,
1308 }
1309 }
1310}
1311
1312impl<S> Iterator for EditSectionLayerObjectsIterator<'_, S>
1313where
1314 S: ReadSectionProvider,
1315{
1316 type Item = (ObjectLayerFrame, ObjectHandle);
1317
1318 fn next(&mut self) -> Option<Self::Item> {
1319 let read_section = self.edit_section.as_read_section();
1320 let Ok(Some(handle)) = read_section.find_object_after(self.layer, self.next_frame) else {
1322 return None;
1323 };
1324
1325 let lf = match read_section.get_object_layer_frame(handle) {
1326 Ok(lf) => lf,
1327 Err(_) => return None,
1328 };
1329
1330 self.next_frame = lf.end.saturating_add(1);
1332
1333 Some((lf, handle))
1334 }
1335}
1336
1337fn effect_key(effect_name: &str, effect_index: usize) -> String {
1338 format!("{effect_name}:{effect_index}")
1339}